<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 先实现h5的api -->
    <!-- pushState 往路由栈中增添一个路径 -->
    <!-- replaceState（替换掉栈顶部的路径） -->
    <button onclick="go('/a')">去a</button>
    <button onclick="go('/b')">去b</button>
    <button onclick="go('a',true)">替换去a</button>
    <button onclick="go('b',true)">替换去b</button>

    <script>
        function createCurrentLocation(base) {
            const {pathname,  search, hash} = window.location
            let pos = base.indexOf('#')
            if (pos > -1) {
                return hash.slice(1) || '/'
            }
            return pathname + search + hash
        }

        function  buildState(back, current,  forward, replaced = false, computedScroll = false) {
            return {
                back,
                current,
                forward,
                replaced,
                computedScroll: computedScroll? {x: window.pageXOffset, y: window.pageYOffset} : {},
                position: window.history.length - 1
            }
        }

        function  useHistoryNavigation(base) {
            const {history, location} = window
            const currentLocation = {
                value: createCurrentLocation(base)
            }
            let historyState = {
                value: history.state
            }
            if(!historyState.value) {
                changeLocation(currentLocation.value,buildState(null,currentLocation.value,null, true),true)
            }
            function changeLocation(to, state, replaced = false) {
                const pos = base.indexOf('#')
                to = pos > -1 ? base + to : to
                window.history[replaced ? 'replaceState' : 'pushState'](state, null, to)
                historyState.value = state
            }
            function push(to, state) {
               const currentState = Object.assign(
                   {},
                   historyState.value,
                   {forward: to, computedScroll: {x: window.pageXOffset, y: window.pageYOffset}}
               )
               changeLocation(currentState.current,currentState,true)

               const nextState = Object.assign({},buildState(currentState.current,to,null))
               changeLocation(to,nextState);
               currentLocation.value = to
            }
            function replace(to, state) {
                const currentState = Object.assign(
                   {},
                   buildState(historyState.value.back,to,historyState.value.forward),
                    state
               )
               changeLocation(to,currentState,true)
               currentLocation.value = to
            }
            return {
                location: currentLocation,
                state: historyState,
                push,
                replace
            }
        }

        function useHistoryListeners({location, state:historyState},base) {
            let listeners = []

            const handler = function ({state}) {
                const to = createCurrentLocation(base)
                const from = location.value
                const fromState = historyState.value

                location.value = to
                historyState.value = state
                listeners.forEach(callback => callback(to,from,{}))
            }
            window.addEventListener('popstate', handler)
            function listen(callback) {
                listeners.push(callback)
            }
            return {
                listen
            }
        }
        function createWebHistory(base = '') {
            const historyNavigation = useHistoryNavigation(base);
            const historyListeners = useHistoryListeners(historyNavigation, base);
            return Object.assign({}, historyNavigation,historyListeners)
        }

        function  createWebHashHistory(base = '') {
            return createWebHistory('#')
        }

      // const routerHistory = createWebHistory();
      const routerHistory = createWebHashHistory('/');

      function go(path, state, replaced = false) {
        routerHistory[replaced ? "replace" : "push"](path, state);
      }
      routerHistory.listen((to, from, options) => {
        console.log(to, from, options);
      });
    </script>
  </body>
</html>
